from rest_framework.response import Response
from rest_framework import status
from rest_framework.viewsets import ModelViewSet
from rest_framework import filters
from django_filters.rest_framework import DjangoFilterBackend
import pymysql
from django.conf import settings
from django.http import StreamingHttpResponse
from random import randint
from django.db import transaction

from equity_mall.utils.pages import MyPage
from equity_admin.serializers_nfc import *
from equity_mall.utils.utils import get_level_list, random_str
from equity_admin.filters import *
from django.utils.encoding import escape_uri_path
from equity_admin.tasks import *


class NFCDeviceModelViewSet(ModelViewSet):

    pagination_class = MyPage
    filter_backends = (filters.SearchFilter, DjangoFilterBackend)
    search_fields = ('merchant__wyfMerchantID', 'merchant__name', 'sn')
    filter_class = NFCDeviceFilter

    def get_queryset(self):
        user = self.request.iser
        level = user.level
        level_id = self.request.query_params.get('level_id', None)
        if level_id:
            try:
                level_list = get_level_list(level)
                level_id = int(level_id)
                if level_id in level_list:
                    level = Level.objects.filter(id=level_id).first()
            except:
                pass
        if level.level == 0:
            queryset = NFCDevice.objects.all()
        elif level.level == 1:
            queryset = NFCDevice.objects.filter(level__prov_id=level.id)
        elif level.level == 2:
            queryset = NFCDevice.objects.filter(level__city_id=level.id)
        elif level.level == 3:
            queryset = NFCDevice.objects.filter(level__district_id=level.id)
        else:
            queryset = NFCDevice.objects.filter(level__branch_id=level.id)
        return queryset.order_by('-id')

    def get_serializer_class(self):
        if self.action == 'list':
            return NFCDeviceListModelSerializer
        else:
            return NFCDeviceRetrieveModelSerializer

    def statistics_time(self, request):
        statistics_time = NFCDeviceStatistics.objects.all().last().trade_time
        return Response({'statistics_time': statistics_time.strftime("%Y-%m-%d 23:59:59")})

    def export_nfc_device(self, request):
        level = self.request.iser
        level_id = self.request.query_params.get('level_id', None)
        search = self.request.query_params.get('search', None)
        device_type = self.request.query_params.get('device_type', None)
        is_lighten = self.request.query_params.get('is_lighten', None)
        rewards_status = self.request.query_params.get('rewards_status', None)
        lighten_time_begin = self.request.query_params.get('lighten_time_begin', None)
        lighten_time_end = self.request.query_params.get('lighten_time_end', None)
        if level_id:
            try:
                level_list = get_level_list(level)
                level_id = int(level_id)
                if level_id in level_list:
                    level = Level.objects.filter(id=level_id).first()
            except:
                pass
        if level.level == 0:
            condition = 'WHERE id!=1'
        elif level.level == 1:
            condition = f'WHERE level_id IN (SELECT id FROM tb_u_level WHERE prov_id={level.id})'
        elif level.level == 2:
            condition = f'WHERE level_id IN (SELECT id FROM tb_u_level WHERE city_id={level.id})'
        elif level.level == 3:
            condition = f'WHERE level_id IN (SELECT id FROM tb_u_level WHERE district_id={level.id})'
        else:
            condition = f'WHERE level_id IN (SELECT id FROM tb_u_level WHERE branch_id={level.id})'
        if search:
            condition = condition + f' AND (sn LIKE "%{search}%")'
        if device_type:
            condition = condition + f' AND device_type IN ({device_type})'
        if lighten_time_begin:
            condition = condition + f' AND lighten_time >= "{lighten_time_begin + " 00:00:00"}"'
        if lighten_time_end:
            condition = condition + f' AND lighten_time <= "{lighten_time_end + " 23:59:59"}"'
        if rewards_status:
            condition = condition + f' AND rewards_status IN ({rewards_status})'
        if is_lighten:
            condition = condition + f' AND is_lighten IN ({is_lighten})'
        conn = pymysql.connect(host=settings.DATABASES['default']['HOST'],
                               port=settings.DATABASES['default']['PORT'],
                               database=settings.DATABASES['default']['NAME'],
                               user=settings.DATABASES['default']['USER'],
                               password=settings.DATABASES['default']['PASSWORD'])
        cursor = conn.cursor(cursor=pymysql.cursors.SSDictCursor)
        try:
            sql = f'''
            SELECT c.*,d.city_name,district_name,branch_name FROM (SELECT a.*,b.business_no,merchant_name FROM (SELECT id,sn,device_type,merchant_id,level_id,DATE_FORMAT(lighten_time,'%Y-%m-%d %H:%i:%S') AS lighten_time,work_user,total_amount,alipay_num,nfc_amount,nfc_num,reach_days,remain_days,distinct_user_num,reach_status,distinct_user_status,rewards_status,reach_list FROM tb_merchant_nfc_device {condition})AS a LEFT JOIN (SELECT id,business_no,merchant_name FROM tb_m_merchant)AS b on a.merchant_id=b.id)AS c LEFT JOIN (SELECT id,city_name,district_name,branch_name FROM tb_u_level)AS d ON c.level_id=d.id;
            '''
            cursor.execute(sql)
        except Exception as e:
            sql = f'''
            SELECT c.*,d.city_name,district_name,branch_name FROM (SELECT a.*,b.business_no,merchant_name FROM (SELECT id,sn,device_type,merchant_id,level_id,DATE_FORMAT(lighten_time,'%Y-%m-%d %H:%i:%S') AS lighten_time,work_user,total_amount,alipay_num,nfc_amount,nfc_num,reach_days,remain_days,distinct_user_num,reach_status,distinct_user_status,rewards_status,reach_list FROM tb_merchant_nfc_device)AS a LEFT JOIN (SELECT id,business_no,merchant_name FROM tb_m_merchant)AS b on a.merchant_id=b.id)AS c LEFT JOIN (SELECT id,city_name,district_name,branch_name FROM tb_u_level)AS d ON c.level_id=d.id;
            '''
            cursor.execute(sql)
        ziduan = ['id', '设备SN码', '设备类型', '微邮付商户号', '商户名称', '所属市公司', '所属区县', '所属网点', '点亮时间', '作业人员', '设备交易总金额', '设备交易总笔数',
                  'NFC交易总金额', 'NFC交易总笔数', '有效动销天数', '离达标达成天数', '剩余考核天数', '有效去重用户', '动销状态', '去重用户达标状态', '铺设奖励状态',
                  'NFC有效动销笔数序列', '数据统计时间']
        cols = ['id', 'sn', 'device_type', 'business_no', 'merchant_name', 'city_name', 'district_name', 'branch_name',
                'lighten_time', 'work_user', 'total_amount', 'alipay_num', 'nfc_amount', 'nfc_num', 'reach_days', 'leave_reach_days',
                'remain_days', 'distinct_user_num', 'reach_status', 'distinct_user_status', 'rewards_status', 'reach_list', 'statistics_time']
        response = StreamingHttpResponse(self.get_nfc_device_fromat(cols, cursor, conn, ziduan))
        response['Content-Type'] = 'application/octet-stream; charset=gbk'
        response['Content-Disposition'] = "attachment; filename*=utf-8''{}".format(escape_uri_path('NFC设备铺设明细.csv'))
        return response

    def get_nfc_device_fromat(self, cols, cursor, conn, ziduan):
        tmp_str = ""
        # 返回文件的每一列列名
        for col in ziduan:
            tmp_str += '"%s",' % (col)
        yield tmp_str.strip(",") + "\n"
        STATUS_ENUM = {
            0: '未完成',
            1: '已完成',
        }
        DEVICE_TYPE_ENUM = {
            1: '支付宝盒 N5H',
            2: '支付宝盒 N5D',
            3: '支付宝盒 N7HD'
        }
        statistics_time = NFCDeviceStatistics.objects.all().last().trade_time.strftime("%Y-%m-%d 23:59:59")
        while True:
            tmp_str = ""
            row = cursor.fetchone()
            if row is None:
                cursor.close()
                conn.close()
                break
            for col in cols:
                # if col in ['ryx_smid', 'sxf_smid']:
                #     tmp_str += '"\'%s",' % (str(row[col]).encode('GBK', 'ignore').decode('gbk') if row[col] else '')
                if col in ['reach_status', 'distinct_user_status', 'rewards_status']:
                    tmp_str += '"%s",' % (STATUS_ENUM[row[col]])
                elif col == 'device_type':
                    tmp_str += '"%s",' % (DEVICE_TYPE_ENUM[row[col]])
                elif col == 'leave_reach_days':
                    tmp_str += '"%s",' % (20-row['reach_days'])
                elif col == 'statistics_time':
                    tmp_str += '"%s",' % (statistics_time)
                elif col == 'reach_list':
                    if row[col]:
                        tmp_str += "'%s'," % (row[col].replace('[', '').replace(']', '').replace(',', '，'))
                    else:
                        tmp_str += '"%s",' % ''
                elif col in ['total_amount', 'alipay_num', 'nfc_amount', 'reach_days']:
                    tmp_str += '"%s",' % (str(row[col]).encode('GBK', 'ignore').decode('gbk') if row[col] else '0')
                else:
                    tmp_str += '"%s",' % (str(row[col]).encode('GBK', 'ignore').decode('gbk') if row[col] else '')
            yield tmp_str.strip(',') + "\n"

    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        if not instance.merchant:
            return Response({'error': '设备暂未绑定商户'}, status=status.HTTP_400_BAD_REQUEST)
        if not instance.longitude or not instance.latitude:
            return Response({'error': '设备未关联商家经纬度'}, status=status.HTTP_400_BAD_REQUEST)
        chaeck_quest = NFCDeviceBountyQuest.objects.filter(device_id=instance.id, quest_status__in=[0, 1, 3])
        if chaeck_quest:
            return Response({'error': '一台设备不能同时进行多次任务'}, status=status.HTTP_400_BAD_REQUEST)
        amount = self.request.data.get('amount', None)
        validity_type = self.request.data.get('validity_type', None)
        validity_count = self.request.data.get('validity_count', None)
        expired_time = self.request.data.get('expired_time', None)
        if not all([amount, validity_type, validity_count, expired_time]):
            return Response({'error': '缺少必传参数'}, status=status.HTTP_400_BAD_REQUEST)
        try:
            expired_time = datetime.datetime.strptime(expired_time, '%Y-%m-%d %H:%M:%S')
        except:
            return Response({'error': '过期时间格式有误'}, status=status.HTTP_400_BAD_REQUEST)
        if str(validity_type) not in ['1']:
            return Response({'error': '有效期类型有误'}, status=status.HTTP_400_BAD_REQUEST)
        if Decimal(amount) < Decimal('1'):
            return Response({'error': '赏金金额需大于1元'}, status=status.HTTP_400_BAD_REQUEST)
        task_id = f'{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}{"%06d" % randint(0, 999999)}'
        data = {}
        data['task_id'] = task_id
        data['device_id'] = instance.id
        data['merchant_id'] = instance.merchant_id
        data['amount'] = amount
        data['longitude'] = instance.longitude
        data['latitude'] = instance.latitude
        data['validity_type'] = validity_type
        data['validity_count'] = validity_count
        data['expired_time'] = expired_time
        data['quest_status'] = 0
        quest = NFCDeviceBountyQuest.objects.create(**data)
        nfc_device_bounty_quest_subscription_send.delay({'id': quest.id})
        return Response({'success': '发布任务成功', 'id': quest.id}, status=status.HTTP_200_OK)


class MerchantNFCDeviceTradeModelViewSet(ModelViewSet):

    pagination_class = MyPage
    filter_backends = (filters.SearchFilter, DjangoFilterBackend)
    search_fields = ('transaction_id', )
    filter_class = MerchantNFCDeviceTradeFilter
    serializer_class = MerchantNFCDeviceTradeListModelSerializer

    def get_queryset(self):
        user = self.request.iser
        if user.level == 0:
            queryset = MerchantNFCDeviceTrade.objects.all().order_by('-id')
        elif user.level == 1:
            queryset = MerchantNFCDeviceTrade.objects.filter(level__prov_id=user.id).order_by('-id')
        elif user.level == 2:
            queryset = MerchantNFCDeviceTrade.objects.filter(level__city_id=user.id).order_by('-id')
        elif user.level == 3:
            queryset = MerchantNFCDeviceTrade.objects.filter(level__district_id=user.id).order_by('-id')
        elif user.level == 4:
            queryset = MerchantNFCDeviceTrade.objects.filter(level__branch_id=user.id).order_by('-id')
        else:
            level_list = get_level_list(user)
            queryset = MerchantNFCDeviceTrade.objects.filter(level_id__in=level_list).order_by('-id')
        return queryset

    def nfc_trade_tree(self, request):
        statistics_id = self.request.query_params.get('statistics_id', None)
        queryset = self.filter_queryset(self.get_queryset())
        if not statistics_id:
            return Response({'error': '缺少必传参数'}, status=status.HTTP_400_BAD_REQUEST)
        if statistics_id:
            statistics = NFCDeviceStatistics.objects.filter(id=statistics_id).first()
            if statistics:
                trade_time_begin = statistics.trade_time.strftime("%Y-%m-%d 00:00:00")
                trade_time_end = statistics.trade_time.strftime("%Y-%m-%d 23:59:59")
                queryset = queryset.filter(trade_time__gte=trade_time_begin, trade_time__lte=trade_time_end, device_id=statistics.device_id)
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class NFCDeviceBountyQuestModelViewSet(ModelViewSet):

    pagination_class = MyPage
    filter_backends = (filters.SearchFilter, DjangoFilterBackend)
    search_fields = ('device__sn', 'merchant__merchant_name')
    filter_class = NFCDeviceBountyQuestFilter

    def get_queryset(self):
        user = self.request.iser
        level = user.level
        level_id = self.request.query_params.get('level_id', None)
        if level_id:
            try:
                level_list = get_level_list(level)
                level_id = int(level_id)
                if level_id in level_list:
                    level = Level.objects.filter(id=level_id).first()
            except:
                pass
        if level.level == 0:
            queryset = NFCDeviceBountyQuest.objects.all()
        elif level.level == 1:
            queryset = NFCDeviceBountyQuest.objects.filter(level__prov_id=level.id)
        elif level.level == 2:
            queryset = NFCDeviceBountyQuest.objects.filter(level__city_id=level.id)
        elif level.level == 3:
            queryset = NFCDeviceBountyQuest.objects.filter(level__district_id=level.id)
        else:
            queryset = NFCDeviceBountyQuest.objects.filter(level__branch_id=level.id)
        # queryset = NFCDeviceBountyQuest.objects.all()
        return queryset.order_by('-id')

    def get_serializer_class(self):
        if self.action == 'list':
            return NFCDeviceBountyQuestListModelSerializer
        else:
            return NFCDeviceBountyQuestRetrieveModelSerializer

    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        audit_state = self.request.data.get('audit_state', None)
        handle_explain = self.request.data.get('handle_explain', None)
        if instance.quest_status != 3:
            return Response({'error': '赏金任务状态有误'}, status=status.HTTP_400_BAD_REQUEST)
        if not handle_explain:
            return Response({'error': '请上传处理申诉说明'}, status=status.HTTP_400_BAD_REQUEST)
        date_now = datetime.datetime.now()
        schedule = NFCDeviceBountyQuestSchedule.objects.filter(quest_id=instance.id, quest_status=3).first()
        if str(audit_state) == '1':
            activity = CashActivity.objects.get(id=1028)
            amount = instance.amount
            with transaction.atomic():
                save_id = transaction.savepoint()
                try:
                    activity_id = activity.id
                    while True:
                        activity = CashActivity.objects.get(id=activity_id)
                        activity_origin_take_amount = activity.take_amount
                        activity_origin_remain_amount = activity.remain_amount
                        if activity_origin_remain_amount < amount:
                            transaction.savepoint_rollback(save_id)
                            return Response({'error': '活动已达到派发上限'}, status=status.HTTP_400_BAD_REQUEST)
                        activity_new_take_amount = activity_origin_take_amount + amount
                        activity_new_remain_amount = activity_origin_remain_amount - amount
                        result = CashActivity.objects.filter(take_amount=activity_origin_take_amount, remain_amount=activity_origin_remain_amount,id=activity_id).update(take_amount=activity_new_take_amount, remain_amount=activity_new_remain_amount)
                        if result == 0:
                            continue
                        break
                    activity_data = {}
                    activity_data['amount'] = amount
                    activity_data['create_time'] = date_now
                    activity_data['cash_activity_id'] = activity.id
                    activity_data['state'] = 1
                    activity_data['customeruservice_id'] = schedule.customeruservice_id
                    identify = random_str()
                    nonce_str = random_str()
                    activity_data['identify'] = identify
                    activity_data['nonce_str'] = nonce_str
                    activity_data['desc'] = activity.name
                    activity_data['partner_trade_no'] = f'{date_now.strftime("%Y%m%d%H%M%S")}{"%06d" % randint(0, 999999)}{"%06d" % schedule.customeruservice_id}'
                    activity_data['expired_time'] = date_now + datetime.timedelta(hours=11)
                    activity_dat, create = CashActivityData.objects.get_or_create(defaults=activity_data, identify=identify)
                    schedule.award_id = activity_dat.id
                    # schedule.quest_status = 2
                    schedule.success_time = date_now
                    schedule.handle_time = date_now
                    schedule.appeal_status = 2
                    schedule.handle_explain = handle_explain
                    schedule.save()
                    instance.quest_status = 6
                    instance.save()
                except:
                    transaction.savepoint_rollback(save_id)
                    return Response({'error': '系统繁忙,请刷新重试'}, status=status.HTTP_400_BAD_REQUEST)
            transaction.savepoint_commit(save_id)
            return Response({'success': '操作成功'}, status=status.HTTP_200_OK)
        else:
            with transaction.atomic():
                save_id = transaction.savepoint()
                try:
                    instance.quest_status = 6
                    instance.save()
                    # schedule.quest_status = 2
                    schedule.handle_time = date_now
                    schedule.appeal_status = 3
                    schedule.handle_explain = handle_explain
                    schedule.save()
                except:
                    transaction.savepoint_rollback(save_id)
                    return Response({'error': '系统繁忙,请刷新重试'}, status=status.HTTP_400_BAD_REQUEST)
            transaction.savepoint_commit(save_id)
            return Response({'success': '操作成功'}, status=status.HTTP_200_OK)

    def partial_update(self, request, *args, **kwargs):
        instance = self.get_object()
        if instance.quest_status != 0:
            return Response({'error': '赏金任务状态有误'}, status=status.HTTP_400_BAD_REQUEST)
        amount = self.request.data.get('amount', None)
        validity_count = self.request.data.get('validity_count', None)
        expired_time = self.request.data.get('expired_time', None)
        quest_status = self.request.data.get('quest_status', None)
        if str(quest_status) == '4':
            instance.quest_status = 4
            instance.save()
            return Response({'success': '操作成功'}, status=status.HTTP_200_OK)
        if amount:
            if Decimal(amount) < Decimal('1'):
                return Response({'error': '赏金金额需大于1元'}, status=status.HTTP_400_BAD_REQUEST)
            instance.amount = amount
        if validity_count:
            instance.validity_count = validity_count
        if expired_time:
            try:
                expired_time = datetime.datetime.strptime(expired_time, '%Y-%m-%d %H:%M:%S')
            except:
                return Response({'error': '过期时间格式有误'}, status=status.HTTP_400_BAD_REQUEST)
            instance.expired_time = expired_time
        instance.save()
        return Response({'success': '操作成功'}, status=status.HTTP_200_OK)


class NFCDeviceBountyQuestScheduleModelViewSet(ModelViewSet):

    pagination_class = MyPage
    filter_backends = (filters.SearchFilter, DjangoFilterBackend)
    # search_fields = ('device__sn', 'merchant__merchant_name')
    filter_class = NFCDeviceBountyQuestScheduleFilter

    def get_queryset(self):
        queryset = NFCDeviceBountyQuestSchedule.objects.all()
        return queryset.order_by('-id')

    def get_serializer_class(self):
        # if self.action == 'list':
        #     return NFCDeviceBountyQuestScheduleListModelSerializer
        # else:
        return NFCDeviceBountyQuestScheduleRetrieveModelSerializer